#include <cstring>
#include <iostream>
#include <string.h>

/*
模板的意义：对类型也可以进行参数化
函数模板 是不进行编译的 因为类型还不知道
模板实例化
在函数调用点，编译器用用户指定的类型或者通过实参推演从原模版实例化一份函数代码出来
模板函数 实例化出来的函数 叫模板函数 这个函数才是编译器所编译的

模板的实参推演  =》 根据用户传入实参类型，推导出模板类型参数

模板类型参数 typename/class
模板非类型参数 bool/char/short/int/long/float/double 都是常量 只能使用 不能修改


模板的特例化（专用化）模板特化
不是由编译器提供的，而是程序员根据特殊类型参数定制的实例化 属于完全特化

模板偏特化
部分模板类型参数特化

模板函数 模板的特例化 非模板函数的重载关系（不算重载关系，函数名不一样）
优先调用非模板函数，然后调用特例化 最后调用模板函数

模板不能在一个文件中定义 而在另一个文件中使用 可以include
但是不能在不同的翻译单元

*/
#if 0
template <typename T> bool compare(T a, T b) {
  std::cout << "template compare" << std::endl;
  return a > b;
}

template <> bool compare(const char *a, const char *b) {
  std::cout << "compare<const char*>()" << std::endl;
  return strcmp(a, b) > 0;
}

bool compare(const char *a, const char *b) {
  std::cout << "normal function" << std::endl;
  return strcmp(a, b) > 0;
}

int main() {
  compare(1, 2);             // template compare
  compare(3.12, 3.14);       // template compare
  compare("hello", "world"); // normal function
}
#endif

/*
类模板
*/

template <typename T> class Stack {
public:
  Stack(int size = 20) {
    _pdata = new T[size];
    _top = -1;
    _size = size;
  }

  ~Stack() {
    delete[] _pdata;
    _pdata = nullptr;
  }

  Stack(const Stack<T> &other) {
    _pdata = new T[other._size];
    for (int i = 0; i <= other._top; i++) {
      _pdata[i] = other._pdata[i];
    }
    _top = other._top;
    _size = other._size;
  }

  Stack(Stack<T> &&other) {
    _pdata = other._pdata;
    _top = other._top;
    _size = other._size;
    other._pdata = nullptr;
    other._top = -1;
    other._size = 0;
  }

  Stack<T> &operator=(const Stack<T> &other) {
    if (this == &other)
      return *this;
    delete[] _pdata;
    _pdata = new T[other._size];
    for (int i = 0; i <= other._top; i++) {
      _pdata[i] = other._pdata[i];
    }
    _top = other._top;
    _size = other._size;
    return *this;
  }

  Stack<T> &operator=(Stack<T> &&other) {
    if (this == &other)
      return *this;
    delete[] _pdata;
    _pdata = other._pdata;
    _top = other._top;
    _size = other._size;
    other._pdata = nullptr;
    other._top = -1;
    other._size = 0;
    return *this;
  }

  void push(const T &val) {
    if (full())
      resize();
    _pdata[++_top] = val;
  }

  void pop() {
    if (empty())
      return;
    --_top;
  }

  T top() const { return _pdata[_top]; }

  bool full() const { return _top == _size - 1; }
  bool empty() const { return _top == -1; }

private:
  void resize() {
    T *ptmp = new T[_size * 2];
    for (int i = 0; i <= _top; i++) {
      ptmp[i] = _pdata[i];
    }
    delete[] _pdata;
    _pdata = ptmp;
    _size *= 2;
  }

private:
  T *_pdata;
  int _top;
  int _size;
};

int main() {
  Stack<int> stack;
  for (int i = 0; i < 5; i++) {
    stack.push(i);
  }
  while (!stack.empty()) {
    std::cout << stack.top() << " ";
    stack.pop();
  }
  std::cout << std::endl;
}